home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gnu / adainc / s-tassta.adb < prev    next >
Text File  |  1996-01-30  |  40KB  |  1,240 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                 GNU ADA RUNTIME LIBRARY (GNARL) COMPONENTS               --
  4. --                                                                          --
  5. --                 S Y S T E M . T A S K I N G . S T A G E S                --
  6. --                                                                          --
  7. --                                  B o d y                                 --
  8. --                                                                          --
  9. --                             $Revision: 1.32 $                            --
  10. --                                                                          --
  11. --           Copyright (c) 1991,1992,1993, FSU, All Rights Reserved         --
  12. --                                                                          --
  13. -- GNARL is free software; you can redistribute it  and/or modify it  under --
  14. -- terms  of  the  GNU  Library General Public License  as published by the --
  15. -- Free Software  Foundation;  either version 2, or (at  your  option)  any --
  16. -- later  version.  GNARL is distributed  in the hope that  it will be use- --
  17. -- ful, but but WITHOUT ANY WARRANTY;  without even the implied warranty of --
  18. -- MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Gen- --
  19. -- eral Library Public License  for more details.  You should have received --
  20. -- a  copy of the GNU Library General Public License along with GNARL;  see --
  21. -- file COPYING.LIB.  If not,  write to the  Free Software Foundation,  675 --
  22. -- Mass Ave, Cambridge, MA 02139, USA.                                      --
  23. --                                                                          --
  24. ------------------------------------------------------------------------------
  25.  
  26. with Ada.Finalization;
  27. --  used to ensure that Complete_Task is called at the end of the program
  28.  
  29. with System.Compiler_Exceptions;
  30. --  Used for,  Compiler_Exceptions.Notify_Exception
  31. --             Null_Exception
  32.  
  33. with System.Compiler_Options;
  34. --  Used for, Main_Priority
  35.  
  36. --  The following two packages are not part of the GNARL proper.  They
  37. --  provide access to a compiler-specific per-task data area.
  38.  
  39. with System.Tasking_Soft_Links;
  40. --  Used for, Abort_Defer, Abort_Undefer, Get_TSD_Address
  41. --  These are procedure pointers to non-tasking routines that use
  42. --  task specific data.  In the absense of tasking, these routines
  43. --  refer to global data.  In the presense of tasking, they must be
  44. --  replaced with pointers to task-specific versions.
  45.  
  46. with System.Task_Specific_Data;
  47. --  Used for, Create_TSD, Destroy_TSD
  48. --  This package provides initialization routines for task specific data.
  49. --  The GNARL must call these to be sure that all non-tasking
  50. --  Ada constructs will work.
  51.  
  52. with System.Error_Reporting;
  53. --  Used for, Error_Reporting.Assert
  54.  
  55. with System.Tasking.Abortion;
  56. --  Used for, Abortion.Defer_Abortion,
  57. --            Abortion.Undefer_Abortion,
  58. --            Abortion.Change_Base_Priority
  59.  
  60. with System.Tasking.Utilities;
  61. --  Used for, Utilities.ATCB_Ptr,
  62. --            Utilities.ATCB_To_ID,
  63. --            Utilities.ID_To_ATCB,
  64. --            Utilities.ATCB_To_Address
  65. --            Utilities."<",
  66. --            Utilities.">=",
  67. --            Utilities."=",
  68. --            Utilities."/=",
  69. --            Utilities.Task_Stage
  70. --            Utilities.Accepting_State
  71. --            Utilities.All_Tasks_List
  72. --            Utilities.Ada_Task_Control_Block
  73. --            Utilities.Task_Error
  74. --            Utilities.ATCB_Init
  75. --            Utilities.Await_Dependents
  76. --            Utilities.Vulnerable_Complete_Activation
  77. --            Utilities.Abort_To_Level
  78. --            Utilities.Abort_Dependents
  79. --            Utilities.Complete
  80. --            Utilities.Check_Exceptions
  81. --            Utilities.Remove_From_All_Tasks_List
  82.  
  83. with System.Task_Memory;
  84. --  Used for, Task_Memory.Low_Level_New,
  85. --            Task_Memory.Unsafe_Low_Level_New,
  86. --            Task_Memory.Low_Level_Free
  87.  
  88. with System.Task_Primitives; use System.Task_Primitives;
  89.  
  90. with Unchecked_Conversion;
  91.  
  92. pragma Elaborate_All (System.Tasking.Utilities);
  93. pragma Elaborate_All (System.Task_Primitives);
  94. pragma Elaborate_All (System.Tasking.Abortion);
  95. pragma Elaborate_All (System.Error_Reporting);
  96. pragma Elaborate_All (System.Compiler_Exceptions);
  97. pragma Elaborate_All (System.Task_Memory);
  98.  
  99. pragma Elaborate_All (System.Tasking_Soft_Links);
  100. --  This must be elaborated first, to prevent its initialization of
  101. --  the global procedure pointers from overwriting the pointers installed
  102. --  by Stages.
  103.  
  104. package body System.Tasking.Stages is
  105.  
  106.    function ID_To_ATCB (ID : Task_ID) return Utilities.ATCB_Ptr
  107.      renames Tasking.Utilities.ID_To_ATCB;
  108.  
  109.    function ATCB_To_ID (Ptr : Utilities.ATCB_Ptr) return Task_ID
  110.      renames Utilities.ATCB_To_ID;
  111.  
  112.    --  Could use "use type" for the following declarations ???
  113.  
  114.    function "=" (L, R : Utilities.ATCB_Ptr) return Boolean
  115.      renames Utilities."=";
  116.  
  117.    function "=" (L, R : Utilities.Task_Stage) return Boolean
  118.      renames Utilities."=";
  119.  
  120.    function ">=" (L, R : Utilities.Task_Stage) return Boolean
  121.      renames Utilities.">=";
  122.  
  123.    function "<" (L, R : Utilities.Task_Stage) return Boolean
  124.      renames Utilities."<";
  125.  
  126.    function "=" (L, R : Utilities.Accepting_State) return Boolean
  127.      renames Utilities."=";
  128.  
  129.    procedure Defer_Abortion renames Abortion.Defer_Abortion;
  130.  
  131.    procedure Undefer_Abortion renames Abortion.Undefer_Abortion;
  132.  
  133.    function Activation_to_ATCB is new
  134.      Unchecked_Conversion (Activation_Chain, Utilities.ATCB_Ptr);
  135.  
  136.    function ATCB_to_Activation is new
  137.      Unchecked_Conversion (Utilities.ATCB_Ptr, Activation_Chain);
  138.  
  139.    function Get_TSD_Address (Dummy : Boolean) return Address;
  140.    --  This procedure returns the task-specific data pointer installed at
  141.    --  task creation time by the GNARL on behalf of the compiler.  A pointer
  142.    --  to this routine replaces the default pointer installed for the
  143.    --  non-tasking case.
  144.    --  The dummy parameter avoids a bug in GNAT.
  145.  
  146.    procedure Init_RTS (Main_Task_Priority : System.Priority);
  147.    --  This procedure initializes the GNARL.  This includes creating
  148.    --  data structures to make the initial thread into the environment
  149.    --  task, setting up handlers for ATC and errors, and
  150.    --  installing tasking versions of certain operations used by the
  151.    --  compiler.  Init_RTS is called during elaboration.
  152.  
  153.    -----------------------------
  154.    -- ATCB related operations --
  155.    -----------------------------
  156.  
  157.    --  The TCB contains a variable size array whose dope vector must be
  158.    --  initialized. This is too complex (and changes too much with changes
  159.    --  in the TCB record) to do explicitely, so a record of the correct size
  160.    --  is declared here and copied into the newly allocated storage.
  161.  
  162.    --  Discriminant checking is disabled to prevent the discriminant in the
  163.    --  newly created record from being checked before a legal value is
  164.    --  assigned to it.
  165.  
  166.    --  How is discriminant checking disabled, I see no pragma Suppress ???
  167.  
  168.    procedure Initialize_ATCB
  169.      (T    : Utilities.ATCB_Ptr;
  170.       Init : Utilities.ATCB_Init);
  171.    --  Initialize fields of a TCB and link into global TCB structures
  172.  
  173.    function New_ATCB
  174.      (Init : Utilities.ATCB_Init)
  175.       return Utilities.ATCB_Ptr;
  176.    --  New_ATCB creates a new ATCB using the low level allocation routines
  177.    --  (essentially a protected version of malloc()).  This is done because
  178.    --  the new operator can be changed by the user, and may involve
  179.    --  allocation from pools (which would limit the number of tasks), might
  180.    --  block on insufficiant memory, or might fragment the user's heap
  181.    --  behind his back.
  182.  
  183.    function Unsafe_New_ATCB
  184.      (Init : Utilities.ATCB_Init)
  185.       return Utilities.ATCB_Ptr;
  186.    --  This creates a new ATCB using unprotected low level allocation routines
  187.    --  (essentially malloc()).  This is done for allocating the ATCB for the
  188.    --  initial task, since this must be done before initializing the low
  189.    --  level tasking, and locks (and hence protected Low_Level_New) cannot
  190.    --  be used until it is.
  191.  
  192.    procedure Free_ATCB (T : in out Utilities.ATCB_Ptr);
  193.    --  Release storage of a previously allocated ATCB
  194.  
  195.    -----------------------------
  196.    -- Other Local Subprograms --
  197.    -----------------------------
  198.  
  199.    procedure Task_Wrapper (Arg : System.Address);
  200.    --  This is the procedure that is called by the GNULL from the
  201.    --  new context when a task is created.  It waits for activation
  202.    --  and then calls the task body procedure.  When the task body
  203.    --  procedure completes, it terminates the task.
  204.  
  205.    procedure Terminate_Dependents (ML : Master_ID := Master_ID'First);
  206.    --  Terminate all dependent tasks of given master level
  207.  
  208.    procedure Vulnerable_Complete_Task;
  209.    --  Complete the calling task.  This procedure must be called with
  210.    --  abortion deferred.
  211.  
  212.    -----------------------------
  213.    -- Finalization management --
  214.    -----------------------------
  215.  
  216.    type Final is new Ada.Finalization.Controlled with null record;
  217.    procedure Finalize (Object : in out Final);
  218.  
  219.    Task_Finalization_Object : Final;
  220.    --  The only purpose of this object is to force a call to Finalize at the
  221.    --  end of the program
  222.  
  223.    procedure Finalize (Object : in out Final) is
  224.    begin
  225.       Complete_Task;
  226.    end Finalize;
  227.  
  228.    ---------------------
  229.    -- Initialize_ATCB --
  230.    ---------------------
  231.  
  232.    procedure Initialize_ATCB
  233.      (T     : Utilities.ATCB_Ptr;
  234.       Init  : Utilities.ATCB_Init)
  235.    is
  236.       Error : Boolean;
  237.    begin
  238.       --  Initialize all fields of the TCB
  239.  
  240.       Initialize_Lock (System.Priority'Last, T.L);
  241.       Initialize_Cond (T.Cond);
  242.       Initialize_Cond (T.Rend_Cond);
  243.       T.Activation_Count := 0;
  244.       T.Awake_Count := 1;                       --  Counting this task.
  245.       T.Awaited_Dependent_Count := 0;
  246.       T.Terminating_Dependent_Count := 0;
  247.       T.Pending_Action := False;
  248.       T.Pending_ATC_Level := ATC_Level_Infinity;
  249.       T.ATC_Nesting_Level := 1;                 --  1 deep; 0 = abnormal.
  250.       T.Deferral_Level := 1;                    --  Start out deferred.
  251.       T.Stage := Utilities.Created;
  252.       T.Exception_To_Raise := Compiler_Exceptions.Null_Exception;
  253.       T.Accepting := Utilities.Not_Accepting;
  254.       T.Aborting := False;
  255.       T.Suspended_Abortably := False;
  256.       T.Call := null;
  257.       T.Elaborated := Init.Elaborated;
  258.       T.Parent := Init.Parent;
  259.       T.Task_Entry_Point := Init.Task_Entry_Point;
  260.       T.Task_Arg := Init.Task_Arg;
  261.       T.Stack_Size := Init.Stack_Size;
  262.       T.Current_Priority := Init.Priority;
  263.       T.Base_Priority := Init.Priority;
  264.       T.Pending_Priority_Change := False;
  265.       T.Activator := Init.Activator;
  266.       T.Master_of_Task := Init.Master_of_Task;
  267.       T.Master_Within := Increment_Master (Init.Master_of_Task);
  268.       T.Terminate_Alternative := false;
  269.  
  270.       for J in 1 .. T.Entry_Num loop
  271.          T.Entry_Queues (J).Head := null;
  272.          T.Entry_Queues (J).Tail := null;
  273.       end loop;
  274.  
  275.       for L in T.Entry_Calls'Range loop
  276.          T.Entry_Calls (L).Next := null;
  277.          T.Entry_Calls (L).Self := ATCB_To_ID (T);
  278.          T.Entry_Calls (L).Level := L;
  279.       end loop;
  280.  
  281.       --  Link the task into the list of all tasks.
  282.  
  283.       if T.Parent /= null then
  284.          Defer_Abortion;
  285.          Write_Lock (Utilities.All_Tasks_L, Error);
  286.       end if;
  287.  
  288.       T.All_Tasks_Link := Utilities.All_Tasks_List;
  289.       Utilities.All_Tasks_List := T;
  290.  
  291.       if T.Parent /= null then
  292.          Unlock (Utilities.All_Tasks_L);
  293.          Undefer_Abortion;
  294.       end if;
  295.    end Initialize_ATCB;
  296.  
  297.    --------------
  298.    -- New_ATCB --
  299.    --------------
  300.  
  301.    function New_ATCB
  302.      (Init : Utilities.ATCB_Init)
  303.       return Utilities.ATCB_Ptr
  304.    is
  305.       subtype Constrained_ATCB is
  306.         Utilities.Ada_Task_Control_Block (Init.Entry_Num);
  307.  
  308.       Initialized_ATCB : Constrained_ATCB;
  309.       T                : Utilities.ATCB_Ptr;
  310.       A                : System.Address;
  311.  
  312.       function Address_to_Pointer is new
  313.         Unchecked_Conversion (System.Address, Utilities.ATCB_Ptr);
  314.  
  315.    begin
  316.       A :=
  317.         Task_Memory.Low_Level_New
  318.           (Constrained_ATCB'Size / System.Storage_Unit);
  319.       T := Address_to_Pointer (A);
  320.       T.all := Initialized_ATCB;
  321.       Initialize_ATCB (T, Init);
  322.       return T;
  323.    end New_ATCB;
  324.  
  325.    ---------------------
  326.    -- Unsafe_New_ATCB --
  327.    ---------------------
  328.  
  329.    function Unsafe_New_ATCB
  330.      (Init : Utilities.ATCB_Init)
  331.       return Utilities.ATCB_Ptr
  332.    is
  333.       subtype Constrained_ATCB is
  334.         Utilities.Ada_Task_Control_Block (Init.Entry_Num);
  335.  
  336.       Initialized_ATCB : Constrained_ATCB;
  337.       T                : Utilities.ATCB_Ptr;
  338.       A                : System.Address;
  339.  
  340.       function Address_to_Pointer is new
  341.         Unchecked_Conversion (System.Address, Utilities.ATCB_Ptr);
  342.  
  343.    begin
  344.       A :=
  345.         Task_Memory.Unsafe_Low_Level_New
  346.           (Constrained_ATCB'Size / System.Storage_Unit);
  347.       T := Address_to_Pointer (A);
  348.       T.all := Initialized_ATCB;
  349.       return T;
  350.    end Unsafe_New_ATCB;
  351.  
  352.    ---------------
  353.    -- Free_ATCB --
  354.    ---------------
  355.  
  356.    procedure Free_ATCB (T : in out Utilities.ATCB_Ptr) is
  357.       function Pointer_to_Address is new
  358.         Unchecked_Conversion (Utilities.ATCB_Ptr, System.Address);
  359.  
  360.    begin
  361.       Finalize_Lock (T.L);
  362.       Finalize_Cond (T.Cond);
  363.       Finalize_Cond (T.Rend_Cond);
  364.       Task_Memory.Low_Level_Free (Pointer_to_Address (T));
  365.    end Free_ATCB;
  366.  
  367.    ---------------------
  368.    -- Get_TSD_Address --
  369.    ---------------------
  370.  
  371.    function Get_TSD_Address (Dummy : Boolean) return Address is
  372.       T : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  373.    begin
  374.       return T.Compiler_Data;
  375.    end Get_TSD_Address;
  376.  
  377.    --------------
  378.    -- Init_RTS --
  379.    --------------
  380.  
  381.    procedure Init_RTS (Main_Task_Priority : System.Priority) is
  382.       T    : Utilities.ATCB_Ptr;
  383.       Init : Utilities.ATCB_Init;
  384.  
  385.    begin
  386.  
  387.       Utilities.All_Tasks_List := null;
  388.       Init.Entry_Num := 0;
  389.       Init.Parent := null;
  390.  
  391.       Init.Task_Entry_Point := null;
  392.  
  393.       Init.Stack_Size := 0;
  394.       Init.Activator := null;
  395.       Stages.Init_Master (Init.Master_of_Task);
  396.       Init.Elaborated := null;
  397.       if Main_Task_Priority = Unspecified_Priority then
  398.          Init.Priority := Default_Priority;
  399.       else
  400.          Init.Priority := Main_Task_Priority;
  401.       end if;
  402.  
  403.       T := Unsafe_New_ATCB (Init);
  404.  
  405.       T.Compiler_Data := Task_Specific_Data.Create_TSD;
  406.       --  This needs to be done as early as possible in the creation
  407.       --  of a task, since the opration of Ada code within the task may
  408.       --  depend on task specific data.
  409.  
  410.       Initialize_LL_Tasks (T.LL_TCB'Access);
  411.       Initialize_ATCB (T, Init);
  412.  
  413.       T.Stage := Utilities.Active;
  414.  
  415.       --  The allocation of the initial task ATCB is different from
  416.       --  that of subsequent ATCBs, which are allocated with ATCB.New_ATCB.
  417.       --  New_ATCB performs all of the functions of Unsafe_New_ATCB
  418.       --  and Initialize_ATCB.  However, it uses GNULLI operations, which
  419.       --  should not be called until after Initialize_LL_Tasks.  Since
  420.       --  Initialize_LL_Tasks needs the initial ATCB, New_ATCB was broken
  421.       --  down into two parts, the first of which alloctes the ATCB without
  422.       --  calling any GNULLI operations.
  423.  
  424.       Set_Own_Priority (T.Current_Priority);
  425.  
  426.       Initialize_Lock (Priority'Last, Utilities.All_Tasks_L);
  427.       --  Initialize the lock used to synchronize chain of all ATCBs.
  428.  
  429.       --  This is not according the the GNULLI, which specifes
  430.       --  access procedure (Context: Pre_Call_State) for the handler.
  431.       --  This may be a mistake in the interface. ???
  432.  
  433.       Install_Abort_Handler (Utilities.Abort_Handler'Access);
  434.  
  435.       --  Install handlers for asynchronous error signals.
  436.  
  437.       --  This is not according the the GNULLI, which specifes
  438.       --  access procedure(...) for the handler.
  439.       --  This may be a mistake in the interface. ???
  440.  
  441.       Install_Error_Handler (Compiler_Exceptions.Notify_Exception'Address);
  442.  
  443.       --  Set up the soft links to tasking services used in the absense of
  444.       --  tasking.  These replace tasking-free defaults.
  445.  
  446.       Tasking_Soft_Links.Abort_Defer := Abortion.Defer_Abortion'Access;
  447.       Tasking_Soft_Links.Abort_Undefer := Abortion.Undefer_Abortion'Access;
  448.       Tasking_Soft_Links.Get_TSD_Address := Get_TSD_Address'Access;
  449.  
  450.       --  Abortion is deferred in a new ATCB, so we need to undefer abortion
  451.       --  at this stage to make the environment task abortable.
  452.  
  453.       Abortion.Undefer_Abortion;
  454.  
  455.    end Init_RTS;
  456.  
  457.    -----------------
  458.    -- Init_Master --
  459.    -----------------
  460.  
  461.    procedure Init_Master (M : out Master_ID) is
  462.    begin
  463.       M := 0;
  464.    end Init_Master;
  465.  
  466.    ----------------------
  467.    -- Increment_Master --
  468.    ----------------------
  469.  
  470.    function Increment_Master (M : Master_ID) return Master_ID is
  471.    begin
  472.       return M + 1;
  473.    end Increment_Master;
  474.  
  475.    ----------------------
  476.    -- Decrement_Master --
  477.    ----------------------
  478.  
  479.    function Decrement_Master (M : Master_ID) return Master_ID is
  480.    begin
  481.       return M - 1;
  482.    end Decrement_Master;
  483.  
  484.    ------------------
  485.    -- Task_Wrapper --
  486.    ------------------
  487.  
  488.    procedure Task_Wrapper (Arg : System.Address) is
  489.       function Address_To_Task_ID is new
  490.         Unchecked_Conversion (System.Address, Utilities.ATCB_Ptr);
  491.       T : Utilities.ATCB_Ptr := Address_To_Task_ID (Arg);
  492.  
  493.    begin
  494.  
  495.       Undefer_Abortion;
  496.  
  497.       --  Call the task body procedure.
  498.  
  499.       T.Task_Entry_Point (T.Task_Arg);
  500.       --  Return here after task finalization
  501.  
  502.       Defer_Abortion;
  503.  
  504.       --  This call won't return. Therefor no need for Undefer_Abortion
  505.  
  506.       Stages.Leave_Task;
  507.  
  508.    exception
  509.  
  510.    --  Only the call to user code (T.Task_Entry_Point) should raise an
  511.    --  exception.  An "at end" handler in the generated code should have
  512.    --  completed the the task, and the exception should not be propagated
  513.    --  further.  Terminate the task as though it had returned.
  514.  
  515.    when Standard'Abort_Signal =>
  516.       Defer_Abortion;
  517.       Stages.Leave_Task;
  518.    when others =>
  519.       Defer_Abortion;
  520.       Stages.Leave_Task;
  521.    end Task_Wrapper;
  522.  
  523.    -----------------
  524.    -- Create_Task --
  525.    -----------------
  526.  
  527.    procedure Create_Task
  528.      (Size          : Size_Type;
  529.       Priority      : Integer;
  530.       Num_Entries   : Task_Entry_Index;
  531.       Master        : Master_ID;
  532.       State         : Task_Procedure_Access;
  533.       Discriminants : System.Address;
  534.       Elaborated    : Access_Boolean;
  535.       Chain         : in out Activation_Chain;
  536.       Created_Task  : out Task_ID)
  537.    is
  538.  
  539.       T, P, S            : Utilities.ATCB_Ptr;
  540.       Init               : Utilities.ATCB_Init;
  541.       Default_Stack_Size : constant Size_Type := 10000;
  542.       Error              : Boolean;
  543.  
  544.    begin
  545.       S := ID_To_ATCB (Self);
  546.  
  547.       if Priority = Unspecified_Priority then
  548.          Init.Priority := Default_Priority;
  549.       else
  550.          Init.Priority := Priority;
  551.       end if;
  552.  
  553.       --  Find parent of new task, P, via master level number.
  554.  
  555.       P := S;
  556.       if P /= null then
  557.          while P.Master_of_Task >= Master loop
  558.             P := P.Parent;
  559.             exit when P = null;
  560.          end loop;
  561.       end if;
  562.  
  563.       Defer_Abortion;
  564.  
  565.       if P /= null then
  566.          Write_Lock (P.L, Error);
  567.  
  568.          if P /= S
  569.            and then P.Awaited_Dependent_Count /= 0
  570.            and then Master = P.Master_Within
  571.          then
  572.             P.Awaited_Dependent_Count := P.Awaited_Dependent_Count + 1;
  573.          end if;
  574.  
  575.          P.Awake_Count := P.Awake_Count + 1;
  576.          Unlock (P.L);
  577.       end if;
  578.  
  579.       Undefer_Abortion;
  580.  
  581.       Init.Entry_Num := Num_Entries;
  582.       Init.Task_Arg := Discriminants;
  583.       Init.Parent := P;
  584.       Init.Task_Entry_Point := State;
  585.  
  586.       if Size = Unspecified_Size then
  587.          Init.Stack_Size := Default_Stack_Size;
  588.       else
  589.          Init.Stack_Size := Size;
  590.       end if;
  591.  
  592.       Init.Activator := S;
  593.       Init.Master_of_Task := Master;
  594.       Init.Elaborated := Elaborated;
  595.       T := New_ATCB (Init);
  596.  
  597.       T.Compiler_Data := Task_Specific_Data.Create_TSD;
  598.       --  This needs to be done as early as possible in the creation
  599.       --  of a task, since the opration of Ada code within the task may
  600.       --  depend on task specific data.
  601.  
  602.       T.Activation_Link := Activation_to_ATCB (Chain);
  603.       Chain := ATCB_to_Activation (T);
  604.  
  605.       T.Aborter_Link := null;
  606.  
  607.       Created_Task := ATCB_To_ID (T);
  608.    end Create_Task;
  609.  
  610.    --------------------
  611.    -- Activate_Tasks --
  612.    --------------------
  613.  
  614.    procedure Activate_Tasks (Chain_Access : Activation_Chain_Access) is
  615.       This_Task      : Utilities.ATCB_Ptr;
  616.       C              : Utilities.ATCB_Ptr;
  617.       All_Elaborated : Boolean := True;
  618.       LL_Entry_Point : Task_Primitives.LL_Task_Procedure_Access;
  619.       Error          : Boolean;
  620.  
  621.    begin
  622.       This_Task := ID_To_ATCB (Self);
  623.  
  624.       C := Activation_to_ATCB (Chain_Access.all);
  625.       while (C /= null) and All_Elaborated loop
  626.          if C.Elaborated /= null and then not C.Elaborated.all then
  627.             All_Elaborated := False;
  628.          end if;
  629.  
  630.          C := C.Activation_Link;
  631.       end loop;
  632.  
  633.       --  Check that all task bodies have been elaborated.
  634.  
  635.       if not All_Elaborated then
  636.          raise Program_Error;
  637.       end if;
  638.  
  639.       Defer_Abortion;
  640.  
  641.       Write_Lock (This_Task.L, Error);
  642.       This_Task.Activation_Count := 0;
  643.  
  644.       --  Wake up all the tasks so that they can activate themselves.
  645.  
  646.       LL_Entry_Point := Task_Wrapper'Access;
  647.  
  648.       C := Activation_to_ATCB (Chain_Access.all);
  649.       while C /= null loop
  650.  
  651.          Write_Lock (C.L, Error);
  652.  
  653.          --  Note that the locks of the activator and created task are locked
  654.          --  here.  This is necessary because C.Stage and
  655.          --  This_Task.Activation_Count have to be synchronized.  This is also
  656.          --  done in Complete_Activation and Init_Abortion.  So long as the
  657.          --  activator lock is always locked first, this cannot lead to
  658.          --  deadlock.
  659.  
  660.          if C.Stage = Utilities.Created then
  661.  
  662.             --  Create the task
  663.             --  Actual creation of LL_Task is defered until the activation
  664.             --  time
  665.  
  666.             --  Ask for 4 extra bytes of stack space so that the ATCB
  667.             --  pointer can be stored below the stack limit, plus extra
  668.             --  space for the frame of Task_Wrapper.  This is so the use
  669.             --  gets the amount of stack requested exclusive of the needs
  670.             --  of the runtime.
  671.  
  672.             Create_LL_Task (
  673.               System.Priority (C.Current_Priority),
  674.               Task_Primitives.Task_Storage_Size (
  675.               Integer (C.Stack_Size) +
  676.               Integer (Task_Primitives.Task_Wrapper_Frame) + 4),
  677.               LL_Entry_Point,
  678.               Utilities.ATCB_To_Address (C),
  679.               C.LL_TCB'Access);
  680.  
  681.             C.Stage := Utilities.Can_Activate;
  682.             This_Task.Activation_Count := This_Task.Activation_Count + 1;
  683.  
  684.          end if;
  685.  
  686.          Unlock (C.L);
  687.  
  688.          C := C.Activation_Link;
  689.       end loop;
  690.  
  691.       This_Task.Suspended_Abortably := True;
  692.       while This_Task.Activation_Count > 0 loop
  693.          if This_Task.Pending_Action then
  694.             if This_Task.Pending_Priority_Change then
  695.                Abortion.Change_Base_Priority (This_Task);
  696.             end if;
  697.  
  698.             exit when
  699.                This_Task.Pending_ATC_Level < This_Task.ATC_Nesting_Level;
  700.             This_Task.Pending_Action := False;
  701.          end if;
  702.          Cond_Wait (This_Task.Cond, This_Task.L);
  703.       end loop;
  704.       This_Task.Suspended_Abortably := False;
  705.  
  706.       Unlock (This_Task.L);
  707.  
  708.       Chain_Access.all := null;
  709.       --  After the activation, tasks should be removed from the Chain
  710.  
  711.       Undefer_Abortion;
  712.       Utilities.Check_Exception;
  713.    end Activate_Tasks;
  714.  
  715.    -------------------------------
  716.    -- Expunge_Unactivated_Tasks --
  717.    -------------------------------
  718.  
  719.    procedure Expunge_Unactivated_Tasks (Chain : in out Activation_Chain) is
  720.       This_Task      : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  721.       C              : Utilities.ATCB_Ptr;
  722.       Temp           : Utilities.ATCB_Ptr;
  723.       Result         : Boolean;
  724.    begin
  725.  
  726.       Defer_Abortion;
  727.  
  728.       C := Activation_to_ATCB (Chain);
  729.  
  730.       while C /= null loop
  731.  
  732.          Error_Reporting.Assert (
  733.            C.Stage <= Utilities.Created,
  734.            "Trying to expunge task which went beyond CREATED stage");
  735.  
  736.          Temp := C;
  737.          C := C.Activation_Link;
  738.  
  739.          Utilities.Complete (ATCB_To_ID (Temp));
  740.          --  This will take care of decrementing parent's Await_Count and
  741.          --  Awaited_Dependent_Count.
  742.  
  743.          Utilities.Remove_From_All_Tasks_List (Temp, Result);
  744.          Error_Reporting.Assert (
  745.            Result,
  746.            "Mismatch between All_Tasks_List and Chain to be expunged");
  747.  
  748.          Free_ATCB (Temp);
  749.          --  Task is out of Chain and All_Tasks_List. It is now safe to
  750.          --  free the storage for ATCB.
  751.  
  752.       end loop;
  753.  
  754.       Chain := null;
  755.  
  756.       Undefer_Abortion;
  757.  
  758.    end Expunge_Unactivated_Tasks;
  759.  
  760.    --------------------
  761.    -- Current_Master --
  762.    --------------------
  763.  
  764.    function Current_Master return Master_ID is
  765.    begin
  766.       return ID_To_ATCB (Self).Master_Within;
  767.    end Current_Master;
  768.  
  769.    ------------------------------
  770.    -- Vulnerable_Complete_Task --
  771.    ------------------------------
  772.  
  773.    --  WARNING : Only call this procedure with abortion deferred.
  774.    --  That's why the name has "Vulnerable" in it.
  775.  
  776.    --  This procedure needs to have abortion deferred while it has the current
  777.    --  task's lock locked.
  778.  
  779.    --  This procedure should be called to complete the current task.  This
  780.    --  should be done for:
  781.    --    normal termination via completion;
  782.    --    termination via unhandled exception;
  783.    --    terminate alternative;
  784.    --    abortion.
  785.  
  786.    procedure Vulnerable_Complete_Task is
  787.       P, T            : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  788.       C               : Utilities.ATCB_Ptr;
  789.       Never_Activated : Boolean;
  790.       Error           : Boolean;
  791.  
  792.    begin
  793.       --  T.Stage can be safely checked for Can_Activate here without
  794.       --  protection, since T does not get to run until Stage is Can_Activate,
  795.       --  and Vulnerable_Complete_Activation will check to see if it has moved
  796.       --  beyond Complete_Activation under the protection of the mutex
  797.       --  before decrementing the activator's Activation_Count.
  798.  
  799.       if T.Stage = Utilities.Can_Activate then
  800.          Utilities.Vulnerable_Complete_Activation (T, Completed => True);
  801.       end if;
  802.  
  803.       --  Note that abortion is deferred (see WARNING above)
  804.  
  805.       Utilities.Complete (ATCB_To_ID (T));
  806.       if T.Stage = Utilities.Created then
  807.          T.Stage := Utilities.Terminated;
  808.       end if;
  809.  
  810.       Write_Lock (T.L, Error);
  811.  
  812.       --  If the task has been awakened due to abortion, this should
  813.       --  cause the dependents to abort themselves and cause the awake
  814.       --  count to go to zero.
  815.  
  816.       if T.Pending_ATC_Level < T.ATC_Nesting_Level
  817.         and then T.Awake_Count /= 0
  818.       then
  819.          Unlock (T.L);
  820.          Utilities.Abort_Dependents (ATCB_To_ID (T));
  821.          Write_Lock (T.L, Error);
  822.       end if;
  823.  
  824.       --  At this point we want to complete tasks created by T and not yet
  825.       --  activated, and also mark those tasks as terminated.
  826.  
  827.       Write_Lock (Utilities.All_Tasks_L, Error);
  828.       Unlock (T.L);
  829.  
  830.       C := Utilities.All_Tasks_List;
  831.  
  832.       while C /= null loop
  833.  
  834.          if C.Parent = T and then C.Stage = Utilities.Created then
  835.             Utilities.Complete (ATCB_To_ID (C));
  836.             C.Stage := Utilities.Terminated;
  837.          end if;
  838.  
  839.          C := C.All_Tasks_Link;
  840.       end loop;
  841.  
  842.       Write_Lock (T.L, Error);
  843.       Unlock (Utilities.All_Tasks_L);
  844.  
  845.       while T.Awake_Count /= 0 loop
  846.          Cond_Wait (T.Cond, T.L);
  847.  
  848.          if T.Pending_ATC_Level < T.ATC_Nesting_Level
  849.            and then T.Awake_Count /= 0
  850.          then
  851.             --  The task may have been awakened to perform abortion.
  852.  
  853.             Unlock (T.L);
  854.             Utilities.Abort_Dependents (ATCB_To_ID (T));
  855.             Write_Lock (T.L, Error);
  856.          end if;
  857.       end loop;
  858.  
  859.       Unlock (T.L);
  860.       Terminate_Dependents;
  861.  
  862.    end Vulnerable_Complete_Task;
  863.  
  864.    ----------------
  865.    -- Leave_Task --
  866.    ----------------
  867.  
  868.    procedure Leave_Task is
  869.       P, T                    : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  870.       Saved_Pending_ATC_Level : ATC_Level_Base;
  871.       Error                   : Boolean;
  872.  
  873.    begin
  874.       Saved_Pending_ATC_Level := T.Pending_ATC_Level;
  875.  
  876.       --  We are about to lose our ATCB. Save special fields for final cleanup.
  877.  
  878.       P := T.Parent;
  879.  
  880.       if P /= null then
  881.          Write_Lock (P.L, Error);
  882.          Write_Lock (T.L, Error);
  883.  
  884.          --  If T has a parent, then setting T.Stage to Terminted and
  885.          --  incrementing/decrementing P.Terminating_Dependent_Count
  886.          --  have to be synchronized here and in Terminate_Dependents.
  887.          --  This is done by locking the parent and dependent locks.  So
  888.          --  long as the parent lock is always locked first, this should not
  889.          --  cause deadlock.
  890.  
  891.          T.Stage := Utilities.Terminated;
  892.  
  893.          if P.Terminating_Dependent_Count > 0
  894.            and then T.Master_of_Task = P.Master_Within
  895.          then
  896.             P.Terminating_Dependent_Count := P.Terminating_Dependent_Count - 1;
  897.  
  898.             if P.Terminating_Dependent_Count = 0 then
  899.                Cond_Signal (P.Cond);
  900.             end if;
  901.          end if;
  902.  
  903.          Task_Specific_Data.Destroy_TSD (T.Compiler_Data);
  904.          --  This should be the last thing done to a TCB, since the correct
  905.          --  operation of compiled code may depend on it.
  906.  
  907.          Unlock (T.L);
  908.          Unlock (P.L);
  909.  
  910.          --  WARNING - Once this lock is unlocked, it should be assumed that
  911.          --  the ATCB has been deallocated. It should not be accessed again.
  912.  
  913.       else
  914.          Write_Lock (T.L, Error);
  915.          T.Stage := Utilities.Terminated;
  916.  
  917.          Task_Specific_Data.Destroy_TSD (T.Compiler_Data);
  918.          --  This should be the last thing done to a TCB, since the correct
  919.          --  operation of compiled code may depend on it.
  920.  
  921.          Unlock (T.L);
  922.       end if;
  923.  
  924.       Exit_LL_Task;
  925.  
  926.    end Leave_Task;
  927.  
  928.    -------------------
  929.    -- Complete_Task --
  930.    -------------------
  931.  
  932.    procedure Complete_Task is
  933.    begin
  934.       Defer_Abortion;
  935.       Vulnerable_Complete_Task;
  936.       Undefer_Abortion;
  937.    end Complete_Task;
  938.  
  939.    -------------------------
  940.    -- Complete_Activation --
  941.    -------------------------
  942.  
  943.    procedure Complete_Activation is
  944.       Dummy : Boolean;
  945.    begin
  946.       Defer_Abortion;
  947.  
  948.       Utilities.Vulnerable_Complete_Activation
  949.         (ID_To_ATCB (Self),
  950.          Completed => False);
  951.  
  952.       Undefer_Abortion;
  953.    end Complete_Activation;
  954.  
  955.    --------------------------
  956.    -- Terminate_Dependents --
  957.    --------------------------
  958.  
  959.    --  WARNING : Only call this procedure with abortion deferred.
  960.    --  This procedure needs to have abortion deferred while it has
  961.    --  the current task's lock locked.  This is indicated by the commented
  962.    --  abortion control calls.  Since it is called from two procedures which
  963.    --  also need abortion deferred, it is left controlled on entry to
  964.    --  this procedure.
  965.    --
  966.    --  This relies that all dependents are passive.
  967.    --  That is, they may be :
  968.  
  969.    --  1) held in COMPLETE_TASK;
  970.    --  2) aborted, with forced-call to COMPLETE_TASK pending;
  971.    --  3) held in terminate-alternative of SELECT.
  972.  
  973.    procedure Terminate_Dependents (ML : Master_ID := Master_ID'First) is
  974.       Failed   : Boolean;
  975.       Taken    : Boolean;
  976.       T        : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  977.       C        : Utilities.ATCB_Ptr;
  978.       Previous : Utilities.ATCB_Ptr;
  979.       Temp     : Utilities.ATCB_Ptr;
  980.       Error    : Boolean;
  981.  
  982.    begin
  983.       Write_Lock (Utilities.All_Tasks_L, Error);
  984.  
  985.       --  Abortion is deferred already (see WARNING above)
  986.  
  987.       Write_Lock (T.L, Error);
  988.  
  989.       --  Count the number of active dependents that must terminate before
  990.       --  proceeding.  If Terminating_Dependent_Count is not zero, then the
  991.       --  dependents have already been counted.  This can occur when a thread
  992.       --  executing this routine is canceled and the cancellation takes effect
  993.       --  when Cond_Wait is called to wait for Terminating_Dependent_Count to
  994.       --  go to zero.  In this case we just skip the count and continue waiting
  995.       --  for the count to go to zero.
  996.  
  997.       if T.Terminating_Dependent_Count = 0 then
  998.          C := Utilities.All_Tasks_List;
  999.  
  1000.          while C /= null loop
  1001.  
  1002.             --  The check for C.Stage=ATCB.Terminated and the increment of
  1003.             --  T.Terminating_Dependent_Count must be synchronized here and in
  1004.             --  Complete_Task using T.L and C.L.  So long as the parent T
  1005.             --  is locked before the dependent C, this should not lead to
  1006.             --  deadlock.
  1007.  
  1008.             if C /= T then
  1009.                Write_Lock (C.L, Error);
  1010.  
  1011.                if C.Parent = T
  1012.                  and then C.Master_of_Task >= ML
  1013.                  and then C.Stage /= Utilities.Terminated
  1014.                then
  1015.                   T.Terminating_Dependent_Count :=
  1016.                     T.Terminating_Dependent_Count + 1;
  1017.                end if;
  1018.  
  1019.                Unlock (C.L);
  1020.             end if;
  1021.  
  1022.             C := C.All_Tasks_Link;
  1023.          end loop;
  1024.       end if;
  1025.  
  1026.       Unlock (T.L);
  1027.  
  1028.       C := Utilities.All_Tasks_List;
  1029.  
  1030.       while C /= null loop
  1031.          if C.Parent = T and then C.Master_of_Task >= ML then
  1032.             Utilities.Complete (ATCB_To_ID (C));
  1033.             Cond_Signal (C.Cond);
  1034.          end if;
  1035.  
  1036.          C := C.All_Tasks_Link;
  1037.       end loop;
  1038.  
  1039.       Unlock (Utilities.All_Tasks_L);
  1040.  
  1041.       Write_Lock (T.L, Error);
  1042.  
  1043.       while T.Terminating_Dependent_Count /= 0 loop
  1044.          Cond_Wait (T.Cond, T.L);
  1045.       end loop;
  1046.  
  1047.       Unlock (T.L);
  1048.  
  1049.       --  We don't wake up for abortion here, since we are already
  1050.       --  terminating just as fast as we can so there is no point.
  1051.  
  1052.       Write_Lock (Utilities.All_Tasks_L, Error);
  1053.       C := Utilities.All_Tasks_List;
  1054.       Previous := null;
  1055.  
  1056.       while C /= null loop
  1057.          if C.Parent = T
  1058.            and then C.Master_of_Task >= ML
  1059.          then
  1060.             if Previous /= null then
  1061.                Previous.All_Tasks_Link := C.All_Tasks_Link;
  1062.             else
  1063.                Utilities.All_Tasks_List := C.All_Tasks_Link;
  1064.             end if;
  1065.  
  1066.             Temp := C;
  1067.             C := C.All_Tasks_Link;
  1068.             Free_ATCB (Temp);
  1069.  
  1070.             --  It is OK to free the ATCB provided that the dependent task
  1071.             --  does not access its ATCB in Complete_Task after signalling its
  1072.             --  parent's (this task) condition variable and unlocking its lock.
  1073.  
  1074.          else
  1075.             Previous := C;
  1076.             C := C.All_Tasks_Link;
  1077.          end if;
  1078.       end loop;
  1079.  
  1080.       Unlock (Utilities.All_Tasks_L);
  1081.    end Terminate_Dependents;
  1082.  
  1083.    ------------------
  1084.    -- Enter_Master --
  1085.    ------------------
  1086.  
  1087.    procedure Enter_Master is
  1088.       T : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  1089.  
  1090.    begin
  1091.       T.Master_Within := Increment_Master (T.Master_Within);
  1092.    end Enter_Master;
  1093.  
  1094.    ---------------------
  1095.    -- Complete_Master --
  1096.    ---------------------
  1097.  
  1098.    procedure Complete_Master is
  1099.       T          : Utilities.ATCB_Ptr := ID_To_ATCB (Self);
  1100.       C          : Utilities.ATCB_Ptr;
  1101.       CM         : Master_ID := T.Master_Within;
  1102.       Taken      : Boolean;
  1103.       Asleep     : Boolean;
  1104.       TAS_Result : Boolean;
  1105.       Error      : Boolean;
  1106.  
  1107.    begin
  1108.       Defer_Abortion;
  1109.  
  1110.       Write_Lock (Utilities.All_Tasks_L, Error);
  1111.  
  1112.       --  Cancel threads of dependent tasks that have not yet started
  1113.       --  activation.
  1114.  
  1115.       C := Utilities.All_Tasks_List;
  1116.  
  1117.       while C /= null loop
  1118.          if C.Parent = T and then C.Master_of_Task = CM then
  1119.             Write_Lock (C.L, Error);
  1120.  
  1121.             --  The only way that a dependent should not have been activated
  1122.             --  at this point is if the master was aborted before it could
  1123.             --  call Activate_Tasks.  Abort such dependents.
  1124.  
  1125.             if C.Stage = Utilities.Created then
  1126.                Unlock (C.L);
  1127.                Utilities.Complete (ATCB_To_ID (C));
  1128.                C.Stage := Utilities.Terminated;
  1129.                --  Task is not yet activated. So, just complete and
  1130.                --  Mark it as Terminated.
  1131.             else
  1132.                Unlock (C.L);
  1133.             end if;
  1134.  
  1135.          end if;
  1136.  
  1137.          C := C.All_Tasks_Link;
  1138.       end loop;
  1139.  
  1140.       --  Note that Awaited_Dependent_Count must be zero at this point.  It is
  1141.       --  initialized to zero, this is the only code that can increment it
  1142.       --  when it is zero, and it will be zero again on exit from this routine.
  1143.  
  1144.       Write_Lock (T.L, Error);
  1145.       C := Utilities.All_Tasks_List;
  1146.  
  1147.       while C /= null loop
  1148.          if C.Parent = T and then C.Master_of_Task = CM then
  1149.             Write_Lock (C.L, Error);
  1150.  
  1151.             if C.Awake_Count /= 0 then
  1152.                T.Awaited_Dependent_Count := T.Awaited_Dependent_Count + 1;
  1153.             end if;
  1154.  
  1155.             Unlock (C.L);
  1156.          end if;
  1157.  
  1158.          C := C.All_Tasks_Link;
  1159.       end loop;
  1160.  
  1161.       Unlock (Utilities.All_Tasks_L);
  1162.  
  1163.       --  If the task has been awakened due to abortion, this should
  1164.       --  cause the dependents to abort themselves and cause
  1165.       --  Awaited_Dependent_Count count to go to zero.
  1166.  
  1167.       if T.Pending_ATC_Level < T.ATC_Nesting_Level
  1168.         and then T.Awaited_Dependent_Count /= 0
  1169.       then
  1170.          Unlock (T.L);
  1171.          Utilities.Abort_Dependents (ATCB_To_ID (T));
  1172.          Write_Lock (T.L, Error);
  1173.       end if;
  1174.  
  1175.       T.Stage := Utilities.Await_Dependents;
  1176.  
  1177.       while T.Awaited_Dependent_Count /= 0 loop
  1178.          Cond_Wait (T.Cond, T.L);
  1179.  
  1180.          if T.Pending_ATC_Level < T.ATC_Nesting_Level
  1181.            and then T.Awaited_Dependent_Count /= 0
  1182.          then
  1183.             --  The task may have been awakened to perform abortion.
  1184.  
  1185.             Unlock (T.L);
  1186.             Utilities.Abort_Dependents (ATCB_To_ID (T));
  1187.             Write_Lock (T.L, Error);
  1188.          end if;
  1189.  
  1190.       end loop;
  1191.  
  1192.       Unlock (T.L);
  1193.  
  1194.       if T.Pending_ATC_Level < T.ATC_Nesting_Level then
  1195.          Undefer_Abortion;
  1196.          Error_Reporting.Assert (False, "Continuing after being aborted!");
  1197.       end if;
  1198.  
  1199.       Terminate_Dependents (CM);
  1200.  
  1201.       T.Stage := Utilities.Active;
  1202.  
  1203.       --  Make next master level up active.  This needs to be done before
  1204.       --  decrementing the master level number, so that tasks finding
  1205.       --  themselves dependent on the current master level do not think that
  1206.       --  this master has been terminated (i.e. Stage=Await_Dependents and
  1207.       --  Awaited_Dependent_Count=0).  This should be safe; the only thing that
  1208.       --  can affect the stage of a task after it has become active is either
  1209.       --  the task itself or abortion, which is deferred here.
  1210.  
  1211.       T.Master_Within := Decrement_Master (CM);
  1212.  
  1213.       --  Should not need protection; can only change if T executes an
  1214.       --  Enter_Master or a Complete_Master.  T is only one task, and cannot
  1215.       --  execute these while executing this.
  1216.  
  1217.       Undefer_Abortion;
  1218.  
  1219.    end Complete_Master;
  1220.  
  1221.    ----------------
  1222.    -- Terminated --
  1223.    ----------------
  1224.  
  1225.    function Terminated (T : Task_ID) return Boolean is
  1226.    begin
  1227.       --  Does not need protection; access is assumed to be atomic.
  1228.       --  Why is this assumption made, is pragma Atomic applied proprly???
  1229.  
  1230.       return ID_To_ATCB (T).Stage = Utilities.Terminated;
  1231.    end Terminated;
  1232.  
  1233.    -----------------------------------
  1234.    -- Tasking System Initialization --
  1235.    -----------------------------------
  1236.  
  1237. begin
  1238.    Init_RTS (Compiler_Options.Main_Priority);
  1239. end System.Tasking.Stages;
  1240.